﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace WebCrawler
{
    internal class BasicGraph : IBasicGraph
    {
        public IList<Vertex> Vertices { get; set; }

        public IList<Vertex> DfsResult { get; set; }

        public IList<Vertex> BfsResult { get; set; }

        public IList<Edge> Edges { get; set; }

        public int Depth { get; set; }

        public int Limit { get; set; }

        public BasicGraph()
        {
            Vertices = new List<Vertex>();
            DfsResult = new List<Vertex>();
            BfsResult = new List<Vertex>();
            Edges = new List<Edge>();
            Depth = 0;
            Limit = 0;
        }

        #region Private Methods

        private void UnMarkAll()
        {
            foreach (Vertex vertex in Vertices)
                vertex.Mark = false;
        }

        private Vertex GetNextUnMarked(IList<Vertex> vertexList)
        {
            Vertex result = null;
            foreach (Vertex vertex in vertexList)
            {
                if (!vertex.Mark)
                {
                    result = vertex;
                    break;
                }
            }
            return result;
        }

        private Edge FindEdge(Vertex from, Vertex to)
        {
            Edge result = null;
            bool found = false;
            Vertex v = FindVertex(from);
            Edge e = null;
            IEnumerator<Edge> i = v.Edges.GetEnumerator();
            while(i.MoveNext() && !found)
            {
                e = (Edge)i.Current;
                if(e.To == to)
                {
                    result = e;
                }
            }
            return result;
        }

        private Vertex FindVertex(Vertex v)
        {
            bool found = false;
            Vertex w = null;
            IEnumerator<Vertex> i = EnumVertices();
            while (i.MoveNext() && !found)
            {
                w = (Vertex)i.Current;
                if (w.Title.Equals(v.Title))
                    found = true;
            }
            return w;
        }

        private void ClearListResult()
        {
            DfsResult = new List<Vertex>();
            BfsResult = new List<Vertex>();
        }

        private void ClearLimitAndDepth()
        {
            Depth = 0;
            Limit = 0;
        }

        #endregion

        #region IBasicGraph Members

        public void AddVertex(Vertex vertex)
        {
            Vertices.Add(vertex);
        }

        public void AddEdge(Vertex startVertex, Vertex endVertex)
        {

            startVertex.AddEdge(endVertex);
            Edges.Add(new Edge(startVertex, endVertex));
        }

        public void RemoveVertex(Vertex v)
        {
            Vertices.Remove(v);
        }

        public void RemoveEdge(Vertex from, Vertex to)
        {
            Edges.Remove(FindEdge(from, to));
        }

        public bool ContainsVertex(Vertex v)
        {
            bool found = false;
            Vertex w = null;
            IEnumerator<Vertex> i = EnumVertices();
            while (i.MoveNext() && !found)
            {
                w = (Vertex)i.Current;
                if (w.Title.Equals(v.Title))
                    found = true;
            }
            return found;
        }

        public bool IsAdjacent(Vertex startVertex, Vertex endVertex)
        {
            bool found = false;
            if(ContainsVertex(startVertex) && ContainsVertex(endVertex))
            {
                if(!found)
                {
                    found = true;
                }

            }
            return found;
        }

        public IList<Vertex> GetAdjacencies(Vertex vertex)
        {
            IList<Vertex> result = new List<Vertex>();
            foreach (Edge edge in FindVertex(vertex).Edges)
            {
                        result.Add(edge.To);
            }
            return result;
        }

        public IEnumerator<Vertex> EnumVertices()
        {
            return Vertices.GetEnumerator();
        }

        public IEnumerator<Edge> EnumEdges()
        {
            return Edges.GetEnumerator();
        }

        public bool IsEmpty()
        {
            bool empty = true;
            if (Vertices.Count != 0)
            {
                empty = false;
            }
            return empty;
        }

        public int GetNoOfVertices()
        {
            return Vertices.Count;
        }

        public int GetNoOfEdges()
        {
            return Edges.Count;
        }

        public void Clear()
        {
            Vertices = new List<Vertex>();
            DfsResult = new List<Vertex>();
            BfsResult = new List<Vertex>();
            Edges = new List<Edge>();
        }

        public IList<Vertex> BreadthFirstSearch(Vertex v, int depth)
        {
            ClearListResult();
            Queue<Vertex> q = new Queue<Vertex>();
            v.Mark = true;
            BfsResult.Add(v);
            Limit = depth;
            q.Enqueue(v);
            while (q.Count != 0 && Depth <= Limit)
            {
                Vertex w = q.Dequeue();
                foreach (Vertex u in GetAdjacencies(w))
                {
                    u.Mark = true;
                    q.Enqueue(u);
                    BfsResult.Add(u);
                }
                Depth++;
            }
            UnMarkAll();
            ClearLimitAndDepth();
            return BfsResult;
        }

        public bool ContainsEdgeTo(Vertex vertex)
        {
            throw new NotImplementedException();
        }

        public IList<Vertex> DepthFirstSearch(Vertex v, int depth)
        {

//            v.Mark = true;
//            Limit = depth;
//            if(GetAdjacencies(v).)
//            foreach (Vertex w in GetAdjacencies(v))
//            {
//                DfsResult.Add(w);
//                w.Mark = true;
//                if(!w.Mark) DepthFirstSearch(w, Limit);
//            }
            UnMarkAll();
            ClearLimitAndDepth();
            return DfsResult;
        }

        #endregion



       
    }
}